const { getLiveServerUrl } = require("./../configuration");

// 1. 打开游戏观察, 应该是固定大小的顶点..
// 2. 不受英雄大小影响
// 3. X Z 轴是向外喷发的 inner
// 4. 面向相机的是一个 [旋转 * 呼吸] 的outer
// 5. 英雄周围有一些体积
// 6. 顶点向外四周发散延伸的一些光效

// Ensure ThreeJS is in global scope for the 'examples/'
global.THREE = require("three");

// Include any additional ThreeJS examples below
require("three/examples/js/controls/OrbitControls");
require("three/examples/js/shaders/CopyShader");
require("three/examples/js/postprocessing/EffectComposer");
require("three/examples/js/postprocessing/RenderPass");
require("three/examples/js/postprocessing/ShaderPass");
require("three/examples/js/postprocessing/TexturePass");
require("three/examples/js/shaders/FXAAShader");

const canvasSketch = require("canvas-sketch");
const glslify = require('glslify');
const { Mesh } = require("three");

const settings = {
  animate: true, // Make the loop animated
  context: "webgl", // Get a WebGL canvas rather than 2D
};

const sketch = ({ context }) => {
  const renderer = new THREE.WebGL1Renderer({ canvas: context.canvas }); // Create a renderer
  renderer.autoClear = false;

  renderer.setClearColor("#fff", 1); // WebGL background color

  const camera = new THREE.PerspectiveCamera(50, 1, 0.01, 100); // Setup a camera
  camera.position.set(0, 0, -4);
  camera.lookAt(new THREE.Vector3());

  const controls = new THREE.OrbitControls(camera, context.canvas); // Setup camera controller
  const textureLoader = new THREE.TextureLoader();

  const scene = new THREE.Scene(); // 这个场景和英雄属于同一个景深检测
  const sceneRediance = new THREE.Scene(); // 这个场景所渲染的平面用来承载辉耀特特效, 不受景深影响

  const composer = new THREE.EffectComposer(renderer);
  composer.passes = [];

  const pass1 = new THREE.RenderPass(sceneRediance, camera);
  composer.addPass(pass1);
  const pass2 = new THREE.RenderPass(scene, camera);
  pass2.clear = false;
  pass2.clearDepth = true;
  composer.addPass(pass2);

  const copyPass = new THREE.ShaderPass(THREE.CopyShader);
  composer.addPass(copyPass);

  const fxaaPass = new THREE.ShaderPass(THREE.FXAAShader);

  const container = document.querySelector('canvas');
  const pixelRatio = renderer.getPixelRatio();

  fxaaPass.material.uniforms['resolution'].value.x = 1 / (container.offsetWidth * pixelRatio);
  fxaaPass.material.uniforms['resolution'].value.y = 1 / (container.offsetHeight * pixelRatio);
  composer.addPass(fxaaPass);

  THREE.ShaderChunk['halo'] =/* glsl */`
        // textureCenter: 中心点 baseLinePos: 与中心点连线以确定基准线 pos: 需要计算的点
        /** 按点到中心点距离来计算颜色 */
        vec3 calculateBaseColorByDistance(vec2 textureCenter, vec2 pos, vec3 color1, vec3 color2) {
            float d = distance(textureCenter, pos);
            float sd = smoothstep(0.0, 0.2, d) - smoothstep(0.2, 0.4, d);
            vec3 baseColor = mix(color1, color2, sd);
            return baseColor;
        }
        /** 按点与中心点连线的角度来计算颜色 */
        vec3 calculateBaseColorByDeg(vec2 textureCenter, vec2 baseLinePos, vec2 pos, vec3 color1, vec3 color2) {
            vec2 reference = normalize(baseLinePos - textureCenter);
            vec2 calculting = normalize(pos - textureCenter);
            float cosTheata = dot(reference, calculting);
            float sd = smoothstep(-2.0, 0.0, cosTheata * 2.0) - smoothstep(0.0, 2.0, cosTheata * 2.0);
            vec3 baseColor = mix(color1, color2, sd);
            return baseColor;
        }
    `;

  // role
  const role = new THREE.Group();
  scene.add(role);

  const role_geometry = new THREE.BoxGeometry(1, 2, 1);
  const role_material = new THREE.MeshBasicMaterial({ color: new THREE.Color('#22CEFA') });
  const role_mesh = new THREE.Mesh(role_geometry, role_material);
  role.attach(role_mesh);

  const haloGeometry = new THREE.PlaneGeometry(4, 4);
  // 光环
  const haloMaterial = new THREE.ShaderMaterial({
    transparent: true,
    side: THREE.FrontSide,
    uniforms: {
      "texture1": { value: textureLoader.load(getLiveServerUrl("/assets/resources/bfcf4fa4183f11ec94270a80ff2603de.png")) },
      "texture2": { value: textureLoader.load(getLiveServerUrl("/assets/resources/84531320183f11eca5a80a80ff2603de.png")) },
      "time": { value: 0.0 }
    },
    vertexShader:/* glsl */`
            varying vec2 vUv;
            varying vec3 vPosition;

            void main() {
                vUv = uv;
                vPosition = position;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `,
    fragmentShader: glslify(/* glsl */`
            #include <halo>
            #pragma glslify: noise = require('glsl-noise/simplex/3d');

            varying vec2 vUv;
            varying vec3 vPosition;

            uniform vec3 role_position;
            uniform sampler2D texture1;
            uniform sampler2D texture2;
            uniform float time;

            vec2 texture1Center = vec2(0.5, 0.5);
            vec2 texture2Center = vec2(0.5, 0.5);

            void main() {
                // 纹理
                vec2 xx = vUv - texture1Center; // 旋转
                mat2 rotateM = mat2(cos(time), -sin(time), sin(time), cos(time));
                vec2 xzh = rotateM * xx;
                vec2 texture1GCenter2 = texture1Center + xzh;
                float texture1Alpha = texture2D(texture1, texture1GCenter2).a;
                float texture2Alpha = texture2D(texture2, vUv).a;
                
                // 噪声
                float offset2 = noise(vec3(vUv, time));
                float mask2 = min(texture2Alpha * 0.5 + offset2 * texture2Alpha * 0.6, 1.0);

                vec3 color1 = vec3((50.0 / 255.0), (250.0 / 255.0), (200.0 / 255.0));
                vec3 color2 = vec3((200.0 / 255.0), (250.0 / 255.0), (50.0 / 255.0));
                vec3 color3 = vec3((80.0 / 255.0), (250.0 / 255.0), (170.0 / 255.0));
                vec3 color4 = vec3((170.0 / 255.0), (250.0 / 255.0), (80.0 / 255.0));

                vec2 baseLinePos = vec2(sin(time), cos(time));
                vec3 baseColor1 = calculateBaseColorByDeg(texture2Center, baseLinePos, vUv, color1, color2);
                vec4 halo1Color = vec4(baseColor1, texture1Alpha);
                vec3 baseColor2 = calculateBaseColorByDistance(texture1Center, vUv, color3, color4);
                vec4 halo2Color = vec4(baseColor2, mask2);
                gl_FragColor = mix(halo1Color, halo2Color, 0.75);
            }
        `)
  });
  // 光晕
  const halo1Material = new THREE.ShaderMaterial({
    transparent: true,
    side: THREE.FrontSide,
    uniforms: {
      "texture": { value: textureLoader.load(getLiveServerUrl("/assets/resources/c99347a2183f11eca5a80a80ff2603de.png")) },
      "time": { value: 0.0 }
    },
    vertexShader:/* glsl */`
            varying vec2 vUv;
            varying vec3 vPosition;

            void main() {
                vUv = uv;
                vPosition = position;
                gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
            }
        `,
    fragmentShader:/* glsl */`
            #include <halo>
            varying vec2 vUv;
            varying vec3 vPosition;
            uniform sampler2D texture;
            uniform float time;
            vec2 textureCenter = vec2(0.5, 0.5);
            void main() {
                float textureAlpha = texture2D(texture, vUv).g; // 纹理
                vec3 color1 = vec3((250.0 / 255.0), (100.0 / 255.0), (80.0 / 255.0));
                vec3 color2 = vec3((80.0 / 255.0), (70.0 / 255.0), (250.0 / 255.0));
                vec3 baseColor = calculateBaseColorByDistance(textureCenter, vUv, color1, color2);
                // gl_FragColor = mix(baseColor, texture2Alpha);
                gl_FragColor = vec4(baseColor, textureAlpha);
            }
        `
  })

  // 光环
  const halo = new Mesh(haloGeometry, haloMaterial);
  const m = new THREE.Matrix4();
  m.set(
    1, 0, 0, 0,
    0, Math.cos(-Math.PI / 2), -Math.sin(-Math.PI / 2), 0,
    0, Math.sin(-Math.PI / 2), Math.cos(-Math.PI / 2), 0,
    0, 0, 0, 1
  );
  halo.applyMatrix4(m);
  halo.position.set(0, -1, 0);
  role.attach(halo);

  // 光晕
  const halo1 = new Mesh(haloGeometry, halo1Material);
  sceneRediance.add(halo1);

  // draw each frame
  return {
    // Handle resize events here
    resize({ pixelRatio, viewportWidth, viewportHeight }) {
      renderer.setPixelRatio(pixelRatio);
      renderer.setSize(viewportWidth, viewportHeight, false);
      camera.aspect = viewportWidth / viewportHeight;
      camera.updateProjectionMatrix();
    },
    // Update & render your scene here
    render({ time }) {
      // halo.rotation.z += 0.0023;
      haloMaterial.uniforms.time.value = time;

      const haloSize = 1.2 + 0.3 * Math.sin(time);
      halo1.scale.x = haloSize
      halo1.scale.y = haloSize;
      halo1.scale.z = haloSize;
      halo1.position.copy(role.position); // 同步光晕位置
      halo1.lookAt(camera.position); // 同步光晕朝向

      controls.update();

      composer.render();

      // renderer.clear();
      // renderer.render(sceneRediance, camera);
      // renderer.clearDepth();
      // renderer.render(scene, camera);
    },
    // Dispose of events & renderer for cleaner hot-reloading
    unload() {
      controls.dispose();
      renderer.dispose();
    }
  };
};

canvasSketch(sketch, settings);
